﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.CompilerServices;

namespace DynamicProperties
{
	/// <summary>
	/// Provides storage for <see cref="DynamicPropertyContainer"/> associated with specific reference type objects.
	/// </summary>
	internal class DynamicPropertyContainerStorage
	{
		private ConditionalWeakTable<object, DynamicPropertyContainer> weakTable;

		public DynamicPropertyContainerStorage()
		{
			this.weakTable = new ConditionalWeakTable<object, DynamicPropertyContainer>();
		}

		/// <summary>
		/// Gets <see cref="DynamicPropertyContainer">container</see> linked to given reference type object if exists.
		/// </summary>
		/// <param name="reference">Reference to key object.</param>
		/// <returns><see cref="DynamicPropertyContainer"/> linked to given reference or null.</returns>
		public DynamicPropertyContainer GetContainer(object reference)
		{
			if (reference == null)
				throw new ArgumentNullException("reference");

			DynamicPropertyContainer result;

			// get from weak table
			if(this.weakTable.TryGetValue(reference, out result))
			{
				// found
				return result;
			}

			// not found
			return null;
		}

		/// <summary>
		/// Gets or creates <see cref="DynamicPropertyContainer">container</see> linked to given reference type object if exists.
		/// </summary>
		/// <param name="reference">Reference to key object.</param>
		/// <returns><see cref="DynamicPropertyContainer"/> linked to given reference or null.</returns>
		public DynamicPropertyContainer GetOrCreateContainer(object reference)
		{
			if (reference == null)
				throw new ArgumentNullException("reference");

			DynamicPropertyContainer result;

			// get or create from weak table
			result = this.weakTable.GetOrCreateValue(reference);

			return result;
		}

		/// <summary>
		/// Removes <see cref="DynamicPropertyContainer"/> associated with given reference type object.
		/// </summary>
		/// <param name="reference">Reference to key object.</param>
		/// <returns>Returns true if associated <see cref="DynamicPropertyContainer"/> was removed.</returns>
		public bool RemoveContainer(object reference)
		{
			if (reference == null)
				throw new ArgumentNullException("reference");

			bool result;

			// remove from weak table
			result = this.weakTable.Remove(reference);
	
			return result;
		}
	}
}
